#include "tracimportsettingswidget.h"
#include "ui_tracimportsettingswidget.h"

#include "xmlrpcbase64.h"
#include "xmlrpcconnection.h"
#include "xmlrpcparser.h"
#include "xmlrpcrequest.h"
#include "xmlrpcresponse.h"

#include "tracsettings.h"
#include "informationwidget.h"

#include <utils/synchronousprocess.h>
#include <coreplugin/icore.h>

#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include <QtCore/QSettings>
#include <QtCore/QUrl>

static const char gitGroupC[] = "Git";
static const char gitPathKeyC[] = "Path";
static const char gitSysEnvKeyC[] = "SysEnv";

using XmlRpc::XmlRpcConnection;
using XmlRpc::XmlRpcRequest;
using XmlRpc::XmlRpcBase64;

namespace Trac {
namespace Internal {

TracImportSettingsWidget::TracImportSettingsWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TracImportSettingsWidget),
    m_valid(false),
    m_connection(new XmlRpcConnection(this)),
    m_infoWidget(0)
{
    ui->setupUi(this);

    m_infoWidget = new InformationWidget(this);
    ui->gridLayout->addWidget(m_infoWidget, 0, 0, 1, ui->gridLayout->columnCount());

    connect(ui->browsePushButton, SIGNAL(clicked()),
            this, SLOT(browse()));
    connect(ui->cloneUrlLineEdit, SIGNAL(textChanged(QString)),
            this, SLOT(checkIsValid()));
    connect(ui->branchComboBox, SIGNAL(currentIndexChanged(int)),
            this, SLOT(checkIsValid()));
    connect(ui->checkoutPathChooser, SIGNAL(changed(QString)),
            this, SLOT(checkIsValid()));
    ui->checkoutPathChooser->buttonAtIndex(0)->setVisible(false);
    connect(ui->checkoutDirectoryLineEdit, SIGNAL(textChanged(QString)),
            this, SLOT(checkIsValid()));
    connect(m_connection, SIGNAL(finished(XmlRpc::XmlRpcResponse*)),
            this, SLOT(rpcQueryCompleted(XmlRpc::XmlRpcResponse*)));

}

TracImportSettingsWidget::~TracImportSettingsWidget()
{
    delete ui;
}

void TracImportSettingsWidget::initialize()
{

    ui->cloneUrlLineEdit->blockSignals(true);
    //ui->branchComboBox->blockSignals(true);
    ui->checkoutPathChooser->blockSignals(true);
    ui->checkoutDirectoryLineEdit->blockSignals(true);

    ui->cloneUrlLineEdit->clear();
    //ui->branchComboBox->clear();
    ui->checkoutPathChooser->lineEdit()->clear();
    ui->checkoutDirectoryLineEdit->clear();

    m_connection->setUrl(TracSettings::instance()->hostName());
    m_connection->setUsername(TracSettings::instance()->username());
    m_connection->setPassword(TracSettings::instance()->password());
    m_currentProjectIdentifier = TracSettings::instance()->checkoutDirectory();

    ui->cloneUrlLineEdit->blockSignals(false);
    //ui->branchComboBox->blockSignals(false);
    ui->checkoutPathChooser->blockSignals(false);
    ui->checkoutDirectoryLineEdit->blockSignals(false);


    openProject();

}

bool TracImportSettingsWidget::isValid() const
{
    return m_valid;
}

const QString TracImportSettingsWidget::currentProjectIdentifier()
{
    return m_currentProjectIdentifier;
}

void TracImportSettingsWidget::openProject()
{
    QVariantList parameters;

    m_request.setMethod(Constants::RPC_OPENPROJECT);

    parameters << TracSettings::instance()->checkoutDirectory() << "" << ""; // Parameters revision and extensionlist left blank
    m_request.setParams(parameters);
    m_connection->query(m_request);
}

void TracImportSettingsWidget::browse()
{

    QString newCheckoutPath = QFileDialog::getExistingDirectory(this,
                                                                tr("Open Directory"),
                                                                TracSettings::instance()->workingPath(),
                                                                QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);

    if(!newCheckoutPath.isEmpty())
        ui->checkoutPathChooser->setPath(newCheckoutPath);

}

void TracImportSettingsWidget::checkIsValid()
{

    bool urlIsValid = validateCloneUrlLineEdit();
    bool pathIsValid = validateCheckoutPathChooser();
    bool directoryIsValid = validateCheckoutDirectoryLineEdit();

    if(urlIsValid && pathIsValid && directoryIsValid) {
        if(m_valid == false) {
            m_valid = true;
            emit validChanged(m_valid);
        }
    }
    else {
        if(m_valid == true) {
            m_valid = false;
            emit validChanged(m_valid);
        }
    }

}

void TracImportSettingsWidget::rpcQueryCompleted(XmlRpc::XmlRpcResponse *response)
{

    if(response->error()) {

        QString errorString;
        QMessageBox errorMsgBox;

        errorString = QString(tr("ERROR (%1): %2")).arg(response->errorCode())
                      .arg(response->errorString());

        errorMsgBox.setText("Query error");
        errorMsgBox.setInformativeText(errorString);
        errorMsgBox.setStandardButtons(QMessageBox::Ok);
        errorMsgBox.setDefaultButton(QMessageBox::Ok);
        errorMsgBox.exec();
    } else {
        QVariantList values = response->returnValue().toList();

        if (response->methodCalled() == Constants::RPC_OPENPROJECT) {
            if (values.count() > 0)
                parseSettings(TracSettings::instance(), values);
            else
                m_infoWidget->display(tr("Unable to retrieve remote settings, "
                                      "invalid XML RPC response.\nYou can fill in the version "
                                      "control URL manually."), "", 0, 0, 0);
            checkIsValid();
        }
    }
    response->deleteLater();
}

// Done similar to git plugin
QString gitPath()
{
    Core::ICore *core = Core::ICore::instance();
    if (QSettings *s = core->settings()) {
        s->beginGroup(QLatin1String(gitGroupC));
        const QString path = s->value(QLatin1String(gitPathKeyC), QString()).toString();
        bool adoptPath = s->value(QLatin1String(gitSysEnvKeyC), false).toBool();
        s->endGroup();
        const QString binary = QLatin1String(Constants::BINARY_GIT);
        QString currentPath = path;
        if (!adoptPath)
            currentPath = QString::fromLocal8Bit(qgetenv("PATH"));
        const QString pathBinary = Utils::SynchronousProcess::locateBinary(currentPath, binary);
        if (pathBinary.isEmpty())
            return binary;
        return pathBinary;
    } else {
        return Constants::BINARY_GIT;
    }
}

QString svnPath()
{
    QString rc;
    rc = QLatin1String("svn");
#if defined(Q_OS_WIN32)
    rc.append(QLatin1String(".exe"));
#endif
    Core::ICore *core = Core::ICore::instance();
    if (QSettings *s = core->settings()) {
        const QString binary = s->value(QLatin1String("Subversion/Command"), rc).toString();
        return binary;
    }
    return rc;
}

QString mercurialPath()
{
    QString defaultCmd = Constants::BINARY_MERCURIAL;
    Core::ICore *core = Core::ICore::instance();
    if (QSettings *s = core->settings()) {
        const QString binary = s->value(QLatin1String("Mercurial/Mercurial_Path"),
                                        defaultCmd).toString();
        return binary;
    }
    return defaultCmd;
}

static QString getVcsBinaryPath(const QString &binary)
{
    if (binary == Constants::BINARY_GIT)
        return gitPath();
    else if (binary == Constants::BINARY_SUBVERSION)
        return svnPath();
    else if (binary == Constants::BINARY_MERCURIAL)
        return mercurialPath();
    else
        return binary;
}

void TracImportSettingsWidget::parseSettings(TracSettings *instance, QVariantList values)
{
    QString rawString = values.at(0).toString();
    QString binary = rawString.section("|", 1, 1);
    QString url = rawString.remove(0, rawString.lastIndexOf("|") + 1);

    instance->setVcsSystem(binary);

    if (binary == Constants::BINARY_SUBVERSION) {
        instance->setCloneCommand(Constants::CLONECOMMAND_SUBVERSION);
    }
    else if (binary == Constants::BINARY_GIT || binary == Constants::BINARY_MERCURIAL) {
        instance->setCloneCommand(Constants::CLONECOMMAND_GIT_MERCURIAL);

    }

    binary = getVcsBinaryPath(binary);

    instance->setBinary(binary);
    ui->cloneUrlLineEdit->setText(url);
    ui->checkoutPathChooser->setPath(TracSettings::instance()->workingPath());
    ui->checkoutDirectoryLineEdit->setText(TracSettings::instance()->checkoutDirectory());

}


bool TracImportSettingsWidget::validateCloneUrlLineEdit()
{
    QUrl url = ui->cloneUrlLineEdit->text();
    QString authorityAndPath = url.authority() + url.path();
    QPalette palette;

    if(authorityAndPath.contains(QRegExp("[@:]")) || authorityAndPath.isEmpty()) {
        palette.setColor(QPalette::Text, Qt::red);
        ui->cloneUrlLineEdit->setPalette(palette);
        return false;
    }
    else {
        palette.setColor(QPalette::Text, Qt::black);
        ui->cloneUrlLineEdit->setPalette(palette);

        if (TracSettings::instance()->vcsSystem() == Constants::BINARY_GIT ||
                TracSettings::instance()->vcsSystem() == Constants::BINARY_MERCURIAL) {
            url.setUserName(TracSettings::instance()->username().replace(tr("@"), tr("%40")));
            url.setPassword(TracSettings::instance()->password());

            TracSettings::instance()->setCloneUrl(url.toString());
        }
        else if (TracSettings::instance()->vcsSystem() == Constants::BINARY_SUBVERSION) {
            TracSettings::instance()->setCloneUrl(ui->cloneUrlLineEdit->text());
        }

        TracSettings::instance()->setVisibleCloneUrl(ui->cloneUrlLineEdit->text());

        return true;
    }
}

bool TracImportSettingsWidget::validateCheckoutPathChooser()
{
    if(ui->checkoutPathChooser->isValid()) {
        TracSettings::instance()->setWorkingPath(ui->checkoutPathChooser->path());
        return true;
    }
    else
        return false;
}

bool TracImportSettingsWidget::validateCheckoutDirectoryLineEdit()
{
    if(ui->checkoutDirectoryLineEdit->isValid()) {
        TracSettings::instance()->setCheckoutDirectory(ui->checkoutDirectoryLineEdit->text());
        return true;
    }
    else
        return false;
}

} // namespace Internal
} // namespace Trac
